/*
	Copyright (C) 2009 Salil Bhagurkar
	
	This file is part of ViSE
	
	ViSE is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	
	ViSE is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public License
	along with ViSE.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _FS_H_
#define _FS_H_

#include <list.h>

/*The virtual filesystem and the central registry*/


/*There can be three types of nodes. 
1. FS nodes which can be server, client or both, or inactive where the first 3 bits are used and hence the fs mask is 7
2. VDATA nodes. These are the building blocks of the vm and span 4 bits again. The TYPE_VDATA bit is always set if the node is a vdata node
3. Builtin vdata nodes which allow interaction of vdata nodes with the system. These use the higher 8 bits of the type variable and if any of those bits is set, its a builtin

This file only contains the fs types. Refer to vise.h for the remaining types.
*/


#define MAX_BUILTIN_HANDLERS 10

#define TYPE_FSMASK 7

//Simple filesystem node which does not accept or send anything. This is used for stupid undetected hw
//Server/client/both declarations
#define TYPE_FS_SERVER 1
#define TYPE_FS_CLIENT 2
#define TYPE_FS_BOTH 3
#define TYPE_FS 4 //This is a simple classifier


/*Flags below are set along with the above flags. These overlap the vdata flags. Hence
we check if its an fs node and then check for the flags below to find out if they perform any of
these functions. These flags themselves, hence, obviously do not indicate that its an fs node*/
#define TYPE_FS_NOTIFY 8 //This link will get notified when the children change. This is when the driver needs to be notified of devices being added by some other driver.

#define TYPE_FS_ENUM 16 //This is an enumerator and should be called when children need to be enumerated

/*fslink vdata holds a link to an fs node*/


#define FS_NAME_LEN 32
#define MAX_FS_NAME_LEN (FS_NAME_LEN * 20)

static int dummy_fn()
{
	return 0;
}
#define dummy (void *)dummy_fn

//Enumerate op is used in case of a disk filesystem, where we need to tell the fs driver to enumerate the children of a directory when we need to access it.

/*The 'this' parameter in the node_fs structure allows the same function to handle the operations of various nodes in a generic way*/


//These are the flags in 'flag' field
#define HAS_NOTIFIERS 1 //notifiers are registered here
#define HAS_ENUMERATORS 2 //enumerators are registered here
#define ENUMERATED 4 //This indicates that the children have been enumerated already This flag should be cleared when an extenal entity modifies the hd???


struct node_fs {
	u16 type;
	char name[FS_NAME_LEN];
	struct node_fs *links, *linkstail;
	struct node_fs *next, *prev;
	int (*init)(struct node_fs *this);
	int (*deinit)(struct node_fs *this);
	int (*read)(struct node_fs *this, void *buf, u32 offset, u32 count);
	int (*write)(struct node_fs *this, void *buf, u32 offset, u32 count);
	int (*enumerate)(struct node_fs *this);
	int (*notify)(struct node_fs *this, struct node_fs *link);
	u32 op_unit; //The size of one operation Defaults to 1 for disks this is 512 generally
	u8 flags;
	u32 count; //Addressable range of the device
	void *class;
	struct node_fs *parent;
};


int fs_tree(char *s);

//The api:
int fs_link(const char *path,struct node_fs *link);
int fs_noparse_link(struct node_fs *node, struct node_fs *link);
int fs_read(const char *path, void *buf, u32 offset, u32 count);
int fs_write(const char *path, void *buf, u32 offset, u32 count);
int fs_unlink(const char *path,struct node_fs *link);
int fs_noparse_unlink(struct node_fs *node, struct node_fs *link);
struct node_fs *fs_get(const char *path);
struct node_fs *fs_get_relative(struct node_fs *n, const char *path);
char *fs_path(char *s, struct node_fs *node);
struct node_fs *fs_create(char *name);
int fs_move(char *to, char *from);
int fs_noparse_move(struct  node_fs *to, struct node_fs *from);


//Enumerators and notifiers
int fs_noparse_register_enumerator(struct node_fs *n, struct node_fs *x);
int fs_noparse_register_notifier(struct node_fs *n, struct node_fs *x);
int fs_register_enumerator(const char *path, struct node_fs *x);
int fs_register_notifier(const char *path, struct node_fs *x);

struct node_fs *fs_new_enumerator(const char *path, int (*enumerate)(struct node_fs *this), char *name);
struct node_fs *fs_new_notifier(const char *path, int (*notify)(struct node_fs *this, struct node_fs *link), char *name);

struct node_fs *fs_noparse_new_enumerator(struct node_fs *n, int (*enumerate)(struct node_fs *this), char *name);
struct node_fs *fs_noparse_new_notifier(struct node_fs *n, int (*notify)(struct node_fs *this, struct node_fs *link), char *name);



int fs_iterator_parse(struct node_fs **fs, const char *path);
int fs_iterator_get_child(struct node_fs **fs);
int fs_iterator_get_next(struct node_fs **fs);

#define GET_CLASS(fs, type) (type *)fs->class


#define NODE_FS_LIST_INIT .next = NULL, .prev = NULL, .links = NULL, .linkstail=NULL, .parent = NULL
#define INIT_NODE_FS_LIST(n) n->next = n->prev = n->links = n->linkstail = n->parent = NULL

#define NODE_FS_OPS_INIT .read = dummy, .write = dummy, .enumerate = dummy, .notify = dummy
#define INIT_NODE_FS_OPS(n) n->read = n->write = dummy; n->enumerate = dummy; n->notify = dummy

#define NODE_FS_INIT_INIT .init = dummy, .deinit = dummy
#define INIT_NODE_FS_INIT(n) n->init = n->deinit = dummy

#define NODE_FS_INIT_VARS .op_unit = 1, .flags = 0, .count = 0
#define INIT_NODE_FS_VARS(n) n->op_unit = 1; n->flags = 0; n->count = 0


#endif
